﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.Infrastructure.Annotations;
using System.Data.Entity.ModelConfiguration.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AspNetCore.Identity.EntityFramework6
{


    public class IdentityDbContext : IdentityDbContext<IdentityUser>
    {
        /// <summary>
        /// Initializes a new instance of <see cref="IdentityDbContext"/>.
        /// </summary>
        /// <param name="connectString"></param>
        public IdentityDbContext(string connectString) : base(connectString)
        { }
        
    }
    /// <summary>
    /// Base class for the Entity Framework database context used for identity.
    /// </summary>
    /// <typeparam name="TUser">The type of the user objects.</typeparam>
    public class IdentityDbContext<TUser> : IdentityDbContext<TUser,IdentityRole,int,IdentityUserClaim,IdentityUserRole,IdentityUserLogin,IdentityRoleClaim,IdentityUserToken>
        where TUser:IdentityUser
    {
        /// <summary>
        /// Initializes a new instance of <see cref="IdentityDbContext"/>.
        /// </summary>
        /// <param name="connectString"></param>
        public IdentityDbContext(string connectString) : base(connectString)
        { }

        
    }

    //public class IdentityDbContext<TUser, TRole, TKey> :
    //        IdentityDbContext
    //        <TUser, TRole, TKey, IdentityUserClaim<TKey>, IdentityUserRole<TKey>, IdentityUserLogin<TKey>,
    //            IdentityRoleClaim<TKey>, IdentityUserToken<TKey>>
    //    where TUser : IdentityUser<TKey>
    //    where TRole : IdentityRole<TKey>
    //    where TKey : IEquatable<TKey>
    //{
    //    public IdentityDbContext(string connectString) : base(connectString)
    //    { }

        
    //}
    public abstract class IdentityDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : DbContext
       where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin>
       where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
       where TKey : IEquatable<TKey>
       where TUserClaim : IdentityUserClaim<TKey>
       where TUserRole : IdentityUserRole<TKey>
       where TUserLogin : IdentityUserLogin<TKey>
       where TRoleClaim : IdentityRoleClaim<TKey>
       where TUserToken : IdentityUserToken<TKey>
    {
        /// <summary>
        /// Initializes a new instance of <see cref="IdentityDbContext"/>.
        /// </summary>
        /// <param name="ConnectString"></param>
        public IdentityDbContext(string ConnectString) : base(ConnectString)
        { }
        
        /// <summary>
        /// Gets or sets the <see cref="DbSet{TEntity}"/> of Users.
        /// </summary>
        public IDbSet<TUser> Users { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="DbSet{TEntity}"/> of User claims.
        /// </summary>
        public IDbSet<TUserClaim> UserClaims { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="DbSet{TEntity}"/> of User logins.
        /// </summary>
        public IDbSet<TUserLogin> UserLogins { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="DbSet{TEntity}"/> of User roles.
        /// </summary>
        public IDbSet<TUserRole> UserRoles { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="DbSet{TEntity}"/> of User tokens.
        /// </summary>
        public IDbSet<TUserToken> UserTokens { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="DbSet{TEntity}"/> of roles.
        /// </summary>
        public IDbSet<TRole> Roles { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="DbSet{TEntity}"/> of role claims.
        /// </summary>
        public IDbSet<TRoleClaim> RoleClaims { get; set; }

        /// <summary>
        /// Configures the schema needed for the identity framework.
        /// </summary>
        /// <param name="builder">
        /// The builder being used to construct the model for this context.
        /// </param>
        protected override void OnModelCreating(DbModelBuilder builder)
        {
            builder.Entity<TUser>().HasKey(u => u.Id);
            builder.Entity<TUser>().Property(u => u.NormalizedUserName)
                .HasMaxLength(256)
                .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UserNameIndex") {IsUnique = true}));
            builder.Entity<TUser>().Property(u => u.ConcurrencyStamp).IsConcurrencyToken();
            builder.Entity<TUser>().Property(u=>u.NormalizedEmail)
                .HasMaxLength(256)
                .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("EmailIndex") { IsUnique = true }));
            builder.Entity<TUser>().ToTable("AspNetUsers");
            builder.Entity<TUser>().Property(u => u.UserName).HasMaxLength(256);
            builder.Entity<TUser>().Property(u => u.Email).HasMaxLength(256);
            builder.Entity<TUser>().HasMany(u => u.Claims).WithRequired().HasForeignKey(u => u.UserId);
            builder.Entity<TUser>().HasMany(u => u.Logins).WithRequired().HasForeignKey(u => u.UserId);
            builder.Entity<TUser>().HasMany(u => u.Roles).WithRequired().HasForeignKey(u => u.UserId);


            builder.Entity<TRole>().HasKey(u => u.Id);
            builder.Entity<TRole>().Property(u=>u.NormalizedName)
                .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true }));
            builder.Entity<TRole>().ToTable("AspNetRoles");
            builder.Entity<TRole>().Property(u => u.ConcurrencyStamp).IsConcurrencyToken();

            builder.Entity<TRole>().Property(u => u.Name).HasMaxLength(256);
            builder.Entity<TRole>().Property(u => u.NormalizedName).HasMaxLength(256);
            builder.Entity<TRole>().HasMany(u => u.Users).WithRequired().HasForeignKey(u => u.RoleId);
            builder.Entity<TRole>().HasMany(u => u.Claims).WithRequired().HasForeignKey(u => u.RoleId);

            builder.Entity<TRoleClaim>().HasKey(u => u.Id);
            builder.Entity<TRoleClaim>().ToTable("AspNetRoleClaims");

            builder.Entity<TUserRole>().HasKey(r => new {r.UserId, r.RoleId});
            builder.Entity<TUserRole>().ToTable("AspNetUserRoles");

            builder.Entity<TUserLogin>().HasKey(r => new {r.LoginProvider, r.ProviderKey});
            builder.Entity<TUserLogin>().ToTable("AspNetUserLogins");

            builder.Entity<TUserToken>().HasKey(u => new {u.UserId, u.LoginProvider, u.Name});
            builder.Entity<TUserToken>().ToTable("AspNetUserTokens");

            builder.Entity<TUserClaim>().HasKey(u => u.Id);
            builder.Entity<TUserClaim>().ToTable("AspNetUserClaim");

        }
        
    }
}
